package br.ufrn.btest.tests.integration;

import static org.junit.Assert.assertEquals;

import java.io.File;
import java.util.List;
import java.util.Set;

import org.junit.Test;

import br.ufrn.btest.Animation;
import br.ufrn.btest.Animator;
import br.ufrn.btest.BlockBuilder;
import br.ufrn.btest.Partitioner;
import br.ufrn.btest.Report;
import br.ufrn.btest.TestMachineBuilder;
import br.ufrn.btest.criterias.Criteria;
import br.ufrn.btest.criterias.EachChoiceCriteria;
import br.ufrn.btest.criterias.Pairwise;
import br.ufrn.btest.exceptions.AnimationErrorException;
import br.ufrn.btest.parser.Machine;
import br.ufrn.btest.parser.Operation;
import br.ufrn.btest.utils.ConventionTools;
import br.ufrn.btest.utils.FileTools;
import de.be4.classicalb.core.parser.BException;

public class ReportTest {

	
	@Test
	public void shouldGenerateTestReportFileForOperationWithNoReturnVariables() throws AnimationErrorException {
		Machine machine = getMachineInstance("machines/Paperround.mch");
		Operation operationUnderTest = machine.getOperation(0);
		
		BlockBuilder blockBuilder = new BlockBuilder(new Partitioner(operationUnderTest));
		List<List<String>> blocks = blockBuilder.getEquivalentClassesBlocksAsLists();
		
		Criteria testCriteria = new Pairwise(blocks);
		Set<String> combinations = testCriteria.getCombinationsStrings();
		
		TestMachineBuilder testMachineBuilder = new TestMachineBuilder(operationUnderTest, combinations);
		String testMachineContent = testMachineBuilder.generateTestMachine();
		
		String testMachineFilePath = "machines/" + ConventionTools.getTestMachineName(operationUnderTest) + ".mch";
		File testMachineFile = FileTools.createFileWithContent(testMachineFilePath, testMachineContent);
		
		Machine testMachine;
		try {
			testMachine = new Machine(testMachineFile);
		} catch (BException e) {
			testMachine = null;
		}
		
		Animator animator = new Animator(testMachine);
		List<Animation> animations = animator.animateAllOperations();
		
		Report report = new Report(operationUnderTest, animations);
		File generateReportFile = report.generateReportFile();
	
		String reportText = FileTools.getFileContent(generateReportFile);
		
		assertEquals(PAPERROUND_REPORT, reportText);
	}

	
	
	@Test
	public void shouldGenerateTestReportFileForOperationWithReturnVariables() {
		Machine machine = getMachineInstance("machines/Player.mch");
		Operation operationUnderTest = machine.getOperation(1);
		
		BlockBuilder blockBuilder = new BlockBuilder(new Partitioner(operationUnderTest));
		List<List<String>> blocks = blockBuilder.getEquivalentClassesBlocksAsLists();
		
		Criteria testCriteria = new EachChoiceCriteria(blocks);
		Set<String> combinations = testCriteria.getCombinationsStrings();
		
		TestMachineBuilder testMachineBuilder = new TestMachineBuilder(operationUnderTest, combinations);
		String testMachineContent = testMachineBuilder.generateTestMachine();
		
		String testMachineFilePath = "machines/" + ConventionTools.getTestMachineName(operationUnderTest) + ".mch";
		File testMachineFile = FileTools.createFileWithContent(testMachineFilePath, testMachineContent);
		
		Machine testMachine;
		try {
			testMachine = new Machine(testMachineFile);
		} catch (BException e) {
			testMachine = null;
		}
		
		Animator animator = new Animator(testMachine);
		List<Animation> animations = animator.animateAllOperations();
		
		Report report = new Report(operationUnderTest, animations);
		File generateReportFile = report.generateReportFile();
	
		String fileContent = FileTools.getFileContent(generateReportFile);
		
		assertEquals(PLAYER_QUERY_REPORT, fileContent);
	}
	
	
	
	private Machine getMachineInstance(String path) {
		Machine machine;
		try {
			machine = new Machine(new File(path));
		} catch (BException e) {
			machine = null;
		}
		return machine;
	}
	

	
	private static final String PAPERROUND_REPORT = 
		"TEST REPORT" + "\n" +
		"MACHINE: Paperround" + "\n" +
		"/** Test Formula" + "\n" +
		"magazines <: papers &" + "\n" +
		"hh : 1..163 &" + "\n" +
		"card(papers) <= 60 &" + "\n" +
		"papers <: 1..163 &" + "\n" +
		"card(papers) < 60" + "\n" +
		"*/" + "\n" +
		"addPaperTest1() {" + "\n" +
		"set_magazines({});" + "\n" +
		"set_papers({});" + "\n" +
		"addPaper(1);" + "\n" +
		"// Oracle Value must be calculated" + "\n" +
		"expectedValueForMagazines = nil;" + "\n" +
		"actualValueForMagazines = getMagazines();" + "\n" +
		"assertEquals(expectedValueForMagazines, actualValueForMagazines);" + "\n" +
		"expectedValueForPapers = nil;" + "\n" +
		"actualValueForPapers = getPapers();" + "\n" +
		"assertEquals(expectedValueForPapers, actualValueForPapers);" + "\n" +
		"}" + "\n" +
		"" + "\n" +
		"/** Test Formula" + "\n" +
		"magazines <: papers &" + "\n" +
		"hh : 164..168 &" + "\n" +
		"card(papers) <= 60 &" + "\n" +
		"papers <: -4..0 &" + "\n" +
		"card(papers) < 60" + "\n" +
		"*/" + "\n" +
		"addPaperTest2() {" + "\n" +
		"set_magazines({});" + "\n" +
		"set_papers({});" + "\n" +
		"addPaper(164);" + "\n" +
		"// Oracle Value must be calculated" + "\n" +
		"expectedValueForMagazines = nil;" + "\n" +
		"actualValueForMagazines = getMagazines();" + "\n" +
		"assertEquals(expectedValueForMagazines, actualValueForMagazines);" + "\n" +
		"expectedValueForPapers = nil;" + "\n" +
		"actualValueForPapers = getPapers();" + "\n" +
		"assertEquals(expectedValueForPapers, actualValueForPapers);" + "\n" +
		"}" + "\n" +
		"" + "\n" +
		"/** Test Formula" + "\n" +
		"magazines <: papers &" + "\n" +
		"hh : -4..0 &" + "\n" +
		"card(papers) <= 60 &" + "\n" +
		"papers <: 164..168 &" + "\n" +
		"card(papers) < 60" + "\n" +
		"*/" + "\n" +
		"addPaperTest3() {" + "\n" +
		"set_magazines({});" + "\n" +
		"set_papers({});" + "\n" +
		"addPaper(-4);" + "\n" +
		"// Oracle Value must be calculated" + "\n" +
		"expectedValueForMagazines = nil;" + "\n" +
		"actualValueForMagazines = getMagazines();" + "\n" +
		"assertEquals(expectedValueForMagazines, actualValueForMagazines);" + "\n" +
		"expectedValueForPapers = nil;" + "\n" +
		"actualValueForPapers = getPapers();" + "\n" +
		"assertEquals(expectedValueForPapers, actualValueForPapers);" + "\n" +
		"}" + "\n" +
		"" + "\n" +
		"/** Test Formula" + "\n" +
		"magazines <: papers &" + "\n" +
		"hh : -4..0 &" + "\n" +
		"card(papers) <= 60 &" + "\n" +
		"papers <: 1..163 &" + "\n" +
		"card(papers) < 60" + "\n" +
		"*/" + "\n" +
		"addPaperTest4() {" + "\n" +
		"set_magazines({});" + "\n" +
		"set_papers({});" + "\n" +
		"addPaper(-4);" + "\n" +
		"// Oracle Value must be calculated" + "\n" +
		"expectedValueForMagazines = nil;" + "\n" +
		"actualValueForMagazines = getMagazines();" + "\n" +
		"assertEquals(expectedValueForMagazines, actualValueForMagazines);" + "\n" +
		"expectedValueForPapers = nil;" + "\n" +
		"actualValueForPapers = getPapers();" + "\n" +
		"assertEquals(expectedValueForPapers, actualValueForPapers);" + "\n" +
		"}" + "\n" +
		"" + "\n" +
		"/** Test Formula" + "\n" +
		"magazines <: papers &" + "\n" +
		"hh : 164..168 &" + "\n" +
		"card(papers) <= 60 &" + "\n" +
		"papers <: 1..163 &" + "\n" +
		"not(card(papers) < 60)" + "\n" +
		"*/" + "\n" +
		"addPaperTest5() {" + "\n" +
		"set_magazines({});" + "\n" +
		"set_papers({1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60});" + "\n" +
		"addPaper(164);" + "\n" +
		"// Oracle Value must be calculated" + "\n" +
		"expectedValueForMagazines = nil;" + "\n" +
		"actualValueForMagazines = getMagazines();" + "\n" +
		"assertEquals(expectedValueForMagazines, actualValueForMagazines);" + "\n" +
		"expectedValueForPapers = nil;" + "\n" +
		"actualValueForPapers = getPapers();" + "\n" +
		"assertEquals(expectedValueForPapers, actualValueForPapers);" + "\n" +
		"}" + "\n" +
		"" + "\n" +
		"/** Test Formula" + "\n" +
		"magazines <: papers &" + "\n" +
		"hh : 1..163 &" + "\n" +
		"card(papers) <= 60 &" + "\n" +
		"papers <: -4..0 &" + "\n" +
		"card(papers) < 60" + "\n" +
		"*/" + "\n" +
		"addPaperTest6() {" + "\n" +
		"set_magazines({});" + "\n" +
		"set_papers({});" + "\n" +
		"addPaper(1);" + "\n" +
		"// Oracle Value must be calculated" + "\n" +
		"expectedValueForMagazines = nil;" + "\n" +
		"actualValueForMagazines = getMagazines();" + "\n" +
		"assertEquals(expectedValueForMagazines, actualValueForMagazines);" + "\n" +
		"expectedValueForPapers = nil;" + "\n" +
		"actualValueForPapers = getPapers();" + "\n" +
		"assertEquals(expectedValueForPapers, actualValueForPapers);" + "\n" +
		"}" + "\n" +
		"" + "\n"
		;
	
	
	private static final String PLAYER_REPORT_1 = 
				"TEST REPORT" + "\n" +
				"MACHINE: Player" + "\n" +
				
				"substituteTest1() {" + "\n" +
				"set_team({PLAYER1,PLAYER2,PLAYER3,PLAYER4,PLAYER5,PLAYER6,PLAYER7,PLAYER8,PLAYER9,PLAYER10,PLAYER11});" + "\n" +
				"substitute(PLAYER12, PLAYER1);" + "\n" +
				"// Oracle Value must be calculated" + "\n" +
				"expectedValueForTeam = nil;" + "\n" +
				"actualValueForTeam = getTeam();" + "\n" +
				"assertEquals(expectedValueForTeam, actualValueForTeam);" + "\n" +
				"}" + "\n\n" +
				
				"substituteTest2() {" + "\n" +
				"set_team({PLAYER1});" + "\n" +
				"substitute(PLAYER1, PLAYER1);" + "\n" +
				"// Oracle Value must be calculated" + "\n" +
				"expectedValueForTeam = nil;" + "\n" +
				"actualValueForTeam = getTeam();" + "\n" +
				"assertEquals(expectedValueForTeam, actualValueForTeam);" + "\n" +
				"}" + "\n\n" +
				
				"substituteTest3() {" + "\n" +
				"set_team({});" + "\n" +
				"substitute(PLAYER1, PLAYER1);" + "\n" +
				"// Oracle Value must be calculated" + "\n" +
				"expectedValueForTeam = nil;" + "\n" +
				"actualValueForTeam = getTeam();" + "\n" +
				"assertEquals(expectedValueForTeam, actualValueForTeam);" + "\n" +
				"}" + "\n\n" +
				
				"substituteTest4() {" + "\n" +
				"set_team({PLAYER1,PLAYER2,PLAYER3,PLAYER4,PLAYER5,PLAYER6,PLAYER7,PLAYER8,PLAYER9,PLAYER10,PLAYER11});" + "\n" +
				"substitute(PLAYER12, PLAYER12);" + "\n" +
				"// Oracle Value must be calculated" + "\n" +
				"expectedValueForTeam = nil;" + "\n" +
				"actualValueForTeam = getTeam();" + "\n" +
				"assertEquals(expectedValueForTeam, actualValueForTeam);" + "\n" +
				"}" + "\n\n" +
				
				"substituteTest5() {" + "\n" +
				"set_team({PLAYER1,PLAYER2,PLAYER3,PLAYER4,PLAYER5,PLAYER6,PLAYER7,PLAYER8,PLAYER9,PLAYER10,PLAYER11});" + "\n" +
				"substitute(PLAYER1, PLAYER12);" + "\n" +
				"// Oracle Value must be calculated" + "\n" +
				"expectedValueForTeam = nil;" + "\n" +
				"actualValueForTeam = getTeam();" + "\n" +
				"assertEquals(expectedValueForTeam, actualValueForTeam);" + "\n" +
				"}" + "\n\n" +
				"";
	
	
	private static final String PLAYER_REPORT_2 = 
				"TEST REPORT" + "\n" +
				"MACHINE: Player" + "\n" +
				"substituteTest1() {" + "\n" +
				"set_team({PLAYER1,PLAYER2,PLAYER3,PLAYER4,PLAYER5,PLAYER6,PLAYER7,PLAYER8,PLAYER9,PLAYER10,PLAYER11});" + "\n" +
				"substitute(PLAYER12, PLAYER12);" + "\n" +
				"// Oracle Value must be calculated" + "\n" +
				"expectedValueForTeam = nil;" + "\n" +
				"actualValueForTeam = getTeam();" + "\n" +
				"assertEquals(expectedValueForTeam, actualValueForTeam);" + "\n" +
				"}" + "\n" +
				"" + "\n" +
				"substituteTest2() {" + "\n" +
				"set_team({PLAYER1});" + "\n" +
				"substitute(PLAYER2, PLAYER1);" + "\n" +
				"// Oracle Value must be calculated" + "\n" +
				"expectedValueForTeam = nil;" + "\n" +
				"actualValueForTeam = getTeam();" + "\n" +
				"assertEquals(expectedValueForTeam, actualValueForTeam);" + "\n" +
				"}" + "\n" +
				"" + "\n" +
				"substituteTest3() {" + "\n" +
				"set_team({PLAYER1});" + "\n" +
				"substitute(PLAYER1, PLAYER2);" + "\n" +
				"// Oracle Value must be calculated" + "\n" +
				"expectedValueForTeam = nil;" + "\n" +
				"actualValueForTeam = getTeam();" + "\n" +
				"assertEquals(expectedValueForTeam, actualValueForTeam);" + "\n" +
				"}" + "\n" +
				"" + "\n" +
				"substituteTest4() {" + "\n" +
				"set_team({PLAYER1,PLAYER2,PLAYER3,PLAYER4,PLAYER5,PLAYER6,PLAYER7,PLAYER8,PLAYER9,PLAYER10,PLAYER11});" + "\n" +
				"substitute(PLAYER1, PLAYER1);" + "\n" +
				"// Oracle Value must be calculated" + "\n" +
				"expectedValueForTeam = nil;" + "\n" +
				"actualValueForTeam = getTeam();" + "\n" +
				"assertEquals(expectedValueForTeam, actualValueForTeam);" + "\n" +
				"}" + "\n\n";
	
	
	private final static String PLAYER_QUERY_REPORT = 
				"TEST REPORT" + "\n" +
				"MACHINE: Player" + "\n" +
				"/** Test Formula" + "\n" +
				"card(team) = 11 &" + "\n" +
				"pp : PLAYER &" + "\n" +
				"pp : team &" + "\n" +
				"team <: PLAYER" + "\n" +
				"*/" + "\n" +
				"queryTest1() {" + "\n" +
				"set_team({PLAYER1,PLAYER2,PLAYER3,PLAYER4,PLAYER5,PLAYER6,PLAYER7,PLAYER8,PLAYER9,PLAYER10,PLAYER11});" + "\n" +
				"returnValue = query(PLAYER1);" + "\n" +
				"// Oracle Value must be calculated" + "\n" +
				"expectedValue = nil;" + "\n" +
				"assertEquals(expectedValues, returnValue);" + "\n" +
				"}" + "\n\n" +
		
				"/** Test Formula" + "\n" +
				"card(team) = 11 &" + "\n" +
				"not(pp : team) &" + "\n" +
				"pp : PLAYER &" + "\n" +
				"team <: PLAYER" + "\n" +
				"*/" + "\n" +
				"queryTest2() {" + "\n" +
				"set_team({PLAYER1,PLAYER2,PLAYER3,PLAYER4,PLAYER5,PLAYER6,PLAYER7,PLAYER8,PLAYER9,PLAYER10,PLAYER11});" + "\n" +
				"returnValue = query(PLAYER12);" + "\n" +
				"// Oracle Value must be calculated" + "\n" +
				"expectedValue = nil;" + "\n" +
				"assertEquals(expectedValues, returnValue);" + "\n" +
				"}" + "\n\n";
}
